package com.example.springboottest.util;

import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * Zip压缩/解压缩文件工具类
 */
public class Zip4jUtils {

    /**
     * 多文件压缩
     * @param targetName 文件压缩之后输出路径
     * @param filesPath 待压缩的文件路径
     * @param delSrcFile 是否删除源文件
     */
    public static void zipFile(String[] filesPath,String targetName,String targetPath,boolean delSrcFile) throws Exception{
        //文件压缩路径
        ZipFile zipFile = new ZipFile(targetPath + targetName);
        //被压缩的文件路径
        ArrayList<File> filesToAdd = new ArrayList<>();
        for(String filePath : filesPath){
            File file = new File(targetPath + filePath);
            if(!file.exists()){
                throw new Exception("文件不存在，无法进行压缩！");
            }
            filesToAdd.add(file);
        }
        //设置压缩参数
        ZipParameters parameters = setParameters(false,"");
        zipFile.addFiles(filesToAdd, parameters);
        //删除源文件
        if(delSrcFile){
            for(String srcFile : filesPath){
                if(new File(targetPath + srcFile).exists()){
                    if(!new File(targetPath + srcFile).delete()){
                        throw new Exception("多文件压缩，删除源文件失败！");
                    }
                }
            }
        }
    }

    /**
     * 多文件压缩-加密
     * @param targetName 文件压缩之后输出路径
     * @param filesPath 被压缩的文件路径
     * @param password 密码
     * @param delSrcFile 是否删除源文件
     */
    public static void zipFile(String[] filesPath, String targetName, String targetPath,String password,boolean delSrcFile)
            throws Exception{
        //文件压缩路径
        ZipFile zipFile = new ZipFile(targetPath + targetName);
        //被压缩的文件路径
        ArrayList<File> filesToAdd = new ArrayList<>();
        for(String filePath : filesPath){
            File file = new File(targetPath + filePath);
            if(!file.exists()){
                throw new Exception("文件不存在，无法进行压缩！");
            }
            filesToAdd.add(file);
        }
        //设置压缩参数
        ZipParameters parameters = setParameters(true,password);
        zipFile.addFiles(filesToAdd, parameters);
        //删除源文件
        if(delSrcFile){
            for(String srcFile : filesPath){
                if(new File(targetPath + srcFile).exists()){
                    if(!new File(targetPath + srcFile).delete()){
                        throw new Exception("多文件压缩-加密，删除源文件失败！");
                    }
                }
            }
        }
    }



    /**
     * 单文件压缩，将指定路径下的文件压缩至指定zip文件，
     * @param srcFilePath 待压缩文件路径
     * @param targetName 压缩后文件路径
     * @param delSrcFile 是否删除源文件
     */
    public static void zipFileNotDelFile(String srcFilePath,String targetName,String targetPath,boolean delSrcFile) throws Exception {
        ZipFile zipFile = new ZipFile(targetPath + targetName);
        if(!new File(targetPath + srcFilePath).exists()){
            throw new Exception("文件不存在，无法进行压缩！");
        }
        ArrayList<File> filesToAdd = new ArrayList<>();
        filesToAdd.add(new File(targetPath + srcFilePath));
        //设置压缩参数
        ZipParameters parameters = setParameters(false,"");
        //开始压缩
        zipFile.addFiles(filesToAdd, parameters);
        //删除源文件
        if(delSrcFile){
            File file = new File(targetPath + srcFilePath);
            if(file.exists()){
                if(!file.delete()){
                    throw new Exception("压缩文件夹，删除源文件失败！");
                }
            }
        }
    }

    /**
     * 单文件压缩，将指定路径下的文件压缩至指定zip文件，
     * 并以指定密码加密 若密码为空，则不进行加密保护
     * @param srcFilePath 待压缩文件路径
     * @param targetName 压缩后文件路径
     * @param password 加密密码
     * @param delSrcFile 是否删除源文件
     */
    public static void zipFile(String srcFilePath,String targetName, String targetPath,String password, boolean delSrcFile) throws Exception {
        ZipFile zipFile = new ZipFile(targetPath + targetName);
        if(!new File(targetPath + srcFilePath).exists()){
            throw new Exception("文件不存在，无法进行压缩！");
        }
        ArrayList<File> filesToAdd = new ArrayList<File>();
        filesToAdd.add(new File(targetPath + srcFilePath));
        //设置压缩参数
        ZipParameters parameters = setParameters(true,password);
        //开始压缩
        zipFile.addFiles(filesToAdd, parameters);
        //删除源文件
        if(delSrcFile) {
            File file = new File(targetPath + srcFilePath);
            if (file.exists()) {
                if (!file.delete()) {
                    throw new Exception("压缩文件夹，删除源文件失败！");
                }
            }
        }
    }


    /**
     * 压缩文件夹
     * @param targetName 压缩后文件输出压缩包的名称
     * @param srcFilePath 被压缩的文件夹路径
     * @param targetPath 压缩后的文件存放的路径
     * @param delSrcFile 是否删除源文件
     */
    public static void zipDir(String targetName,String srcFilePath,String targetPath, boolean delSrcFile)
            throws Exception{
        ZipFile zipFile = new ZipFile(targetPath + targetName);
        if(!new File(srcFilePath).isDirectory()){
            throw new Exception("文件不存在，无法进行压缩！");
        }
        //设置压缩参数
        ZipParameters parameters = setParameters(false,"");
        zipFile.addFolder(srcFilePath, parameters);
        //删除源文件
        if(delSrcFile){
            File file = new File(srcFilePath);
            if(file.exists()){
                if(!file.delete()){
                    throw new Exception("压缩文件夹，删除源文件失败！");
                }
            }
        }
    }

    /**
     * 压缩文件夹-加密
     * @param targetName 压缩后文件输出路径
     * @param srcFilePath 被压缩的文件夹路径
     * @param password 加密密码
     * @param delSrcFile 是否删除源文件
     */
    public static void zipDir(String targetName,String srcFilePath,String targetPath,String password, boolean delSrcFile)
            throws Exception{
        ZipFile zipFile = new ZipFile(targetPath + targetName);
        if(!new File(targetPath + srcFilePath).exists()){
            throw new Exception("文件不存在，无法进行压缩！");
        }
        //设置压缩参数
        ZipParameters parameters = setParameters(true,password);
        zipFile.addFolder(targetPath + srcFilePath, parameters);
        //删除源文件
        if(delSrcFile){
            File file = new File(targetPath + srcFilePath);
            if(file.exists()){
                if(!file.delete()){
                    throw new Exception("加密压缩文件夹，删除源文件失败！");
                }
            }
        }
    }

    /**
     * 压缩文件列表
     * @param folderToAdd 文件压缩输出路径
     */
    public static void zipShowList(String folderToAdd) throws ZipException{
        ZipFile zipFile = new ZipFile(folderToAdd);
        List<?> fileHeaderList = zipFile.getFileHeaders();
        for (Object header : fileHeaderList) {
            System.out.println("****File Details for: " + ((FileHeader) header).getFileName() + "*****");
            System.out.println("Name: " + ((FileHeader) header).getFileName());
            System.out.println("Compressed Size: " + ((FileHeader) header).getCompressedSize());
            System.out.println("Uncompressed Size: " + ((FileHeader) header).getUncompressedSize());
            System.out.println("CRC: " + ((FileHeader) header).getCrc32());
            System.out.println("************************************************************");
        }

    }

    /**
     * 设置参数，加密和加密方式，压缩级别等
     * @param isEncrypt 是否加密
     * @param password  加密密码
     * @date 2020/9/7 - 15:10
     */
    private static ZipParameters setParameters(boolean isEncrypt, String password) {
        ZipParameters parameters = new ZipParameters();
        //压缩算法
        parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
        //压缩等级
        parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
        if(isEncrypt){
            //开启设置密码
            parameters.setEncryptFiles(true);
            //标准加密
            //parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD);
            //AES加密
            parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
            parameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
            //设置密码
            parameters.setPassword(password);
        }
        return parameters;
    }

    /**
     * 解压zip
     * @param targetName 解压之后输出的路径
     * @param srcPath 需要解压的文件路径
     * @param delSrcFile 是否删除源文件
     */
    public static void unzip(String targetName,String srcPath, String targetPath,boolean delSrcFile) throws Exception{
        ZipFile zipFile = new ZipFile(targetPath + targetName);
        zipFile.extractAll(targetPath + srcPath);
        //删除源文件
        if(delSrcFile){
            File file = new File(targetPath + srcPath);
            if(file.exists()){
                if(!file.delete()){
                    throw new Exception("解压文件，删除源文件失败！");
                }
            }
        }
    }

    /**
     * 解压带密码的zip
     * @param targetName 解压之后输出的路径
     * @param srcPath 需要解压的文件路径
     * @param password 解密密码
     * @param delSrcFile 是否删除源文件
     */
    public static void unzip(String targetName,String srcPath,String targetPath,String password, boolean delSrcFile)
            throws Exception{
        ZipFile zipFile = new ZipFile(targetPath + targetName);
        if (zipFile.isEncrypted()) {
            zipFile.setPassword(password);
        }
        zipFile.extractAll(targetPath + srcPath);
        //删除源文件
        if(delSrcFile){
            File file = new File(targetPath + srcPath);
            if(file.exists()){
                if(!file.delete()){
                    throw new Exception("解压带密码的压缩文件，删除源文件失败！");
                }
            }
        }
    }


}
